package com.runmonk.core.study.concurrent.threadLocal_test;

/**
 * ThreadLocal 线程变量 测试类demo
 * <p>
 * threadLocal总结：
 * 1、Thread类中有一个成员变量属于ThreadLocalMap类(一个定义在ThreadLocal类中的内部类)，它是一个Map，他的key是ThreadLocal实例对象。
 * <p>
 * 2、当为ThreadLocal类的对象set值时，首先获得当前线程的ThreadLocalMap类属性，然后以ThreadLocal类的对象为key，设定value。get值时则类似。
 * <p>
 * 3、ThreadLocal变量的活动范围为某线程，是该线程“专有的，独自霸占”的，对该变量的所有操作均由该线程完成！也就是说，ThreadLocal 不是用来解决共享
 * 对象的多线程访问的竞争问题的，因为ThreadLocal.set() 到线程中的对象是该线程自己使用的对象，其他线程是不需要访问的，也访问不到的。当线程终止后，这些值会作为垃圾回收。
 * <p>
 * 4、由ThreadLocal的工作原理决定了：每个线程独自拥有一个变量，并非是共享的，下面给出一个例子：
 */
public class ThreadLocalTest implements Cloneable {


    public static void main(String[] args) throws InterruptedException {

        /**
         * 测试1
         */
        Bank bank = new Bank();

        Thread1 thread = new Thread1(bank);
        Thread t1 = new Thread(thread);
        t1.start();

        Thread t2 = new Thread(thread);
        t2.start();

        t1.join();
        t2.join();
        System.out.println(bank.get());

        /**
         * 测试2
         */
        final ThreadLocalTest p = new ThreadLocalTest();
        System.out.println(p);
        Thread t = new Thread(new Runnable() {
            public void run() {
                //线程变量
                ThreadLocal<ThreadLocalTest> threadLocal = new ThreadLocal<ThreadLocalTest>();
                System.out.println(threadLocal);
                threadLocal.set(p);
                System.out.println(threadLocal.get());
                threadLocal.remove();
                try {
                    threadLocal.set((ThreadLocalTest) p.clone());
                    System.out.println(threadLocal.get());
                } catch (CloneNotSupportedException e) {
                    e.printStackTrace();
                }
                System.out.println(threadLocal);
            }
        });
        t.start();
    }
}

/**
 * 测试1
 */
class Bank {
    ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
        //重写这里的方法 修改初始值
        @Override
        protected Integer initialValue() {
            return 100;
        }
    };

    public int get() {
        return threadLocal.get();
    }

    public void set() {
        //获得值 并重写set值
        threadLocal.set(threadLocal.get() + 10);
    }

}

/**
 * 线程thread1
 */
class Thread1 implements Runnable {
    Bank bank;

    public Thread1(Bank bank) {
        this.bank = bank;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            bank.set();//threadLocal实例对象作为Key
            System.out.println(Thread.currentThread() + "" + bank.get());
        }
    }
}
